package com.example.sxy.opcuademo;

/**
 * Created by SXY on 2015/11/26.
 */

import android.os.AsyncTask;
import android.util.Log;


import com.prosysopc.ua.ApplicationIdentity;
import com.prosysopc.ua.PkiFileBasedCertificateValidator;
import com.prosysopc.ua.ServiceException;
import com.prosysopc.ua.SessionActivationException;
import com.prosysopc.ua.StatusException;
import com.prosysopc.ua.UserIdentity;
import com.prosysopc.ua.client.MonitoredDataItem;
import com.prosysopc.ua.client.MonitoredDataItemListener;
import com.prosysopc.ua.client.Subscription;
import com.prosysopc.ua.client.UaClient;

import org.opcfoundation.ua.builtintypes.DataValue;
import org.opcfoundation.ua.builtintypes.DateTime;
import org.opcfoundation.ua.builtintypes.LocalizedText;
import org.opcfoundation.ua.builtintypes.NodeId;
import org.opcfoundation.ua.core.ApplicationDescription;
import org.opcfoundation.ua.core.ApplicationType;
import org.opcfoundation.ua.core.Identifiers;
import org.opcfoundation.ua.transport.security.SecurityMode;

import java.net.URISyntaxException;
import java.util.Locale;

/**
 * This is an AsyncTask for connecting to an OPC UA server and reading the server time
 */
public class ConnectAndReadTimeTask extends AsyncTask<String, String, Boolean>
{
    private String applicationName;
    private DateTime time;
    private String value;
    private MainActivity activity;
    private String error;

    /**
     * Creates a new Task
     *
     * @param appName
     */
    public ConnectAndReadTimeTask(MainActivity activity, String appName){
        this.activity = activity;
        this.applicationName = appName;
    }

    /* (non-Javadoc)
     * @see android.os.AsyncTask#doInBackground(Params[])
     *
     * This method is executed in the background, and will do the reading
     */
    protected Boolean doInBackground(String...strings)
    {
        String serverUri = strings[0];
        UaClient myClient;
        try {
            myClient = createClient(serverUri);
            myClient.connect();
        } catch (Exception e) {
            error = e.toString();
            return false;
        }
//        MyEnumObject的NodeID对象
        NodeId enumObjNode = new NodeId(2,"MyEnumObject");
//        DataValue对象为client 读操作返回的对象类型
//        封装了读取的时间、节点、返回值（Variant）信息
        DataValue dv;
        try {
            dv = myClient.readValue(Identifiers.Server_ServerStatus_CurrentTime);
//            获取服务器时间
            time = (DateTime) dv.getValue().getValue();
//            获取MyEnumObject的值value
            value = myClient.readValue(enumObjNode).getValue().getValue().toString();
//            执行写操作
            myClient.writeValue(enumObjNode,999);
        } catch (Exception e) {
            error = e.toString();
            return false;
        }
//        myClient.disconnect();

        return true;
    }

    /**
     * This is an example on how to create and set parameters to an UaClient
     *
     * @param serverUri
     * @return
     * @throws URISyntaxException
     * @throws SessionActivationException
     */
    public UaClient createClient(String serverUri) throws URISyntaxException,
            SessionActivationException {
        // Create the UaClient
        UaClient myClient = new UaClient(serverUri);

        // Create and set certificate validator
        PkiFileBasedCertificateValidator validator = new PkiFileBasedCertificateValidator("/sdcard/PKI/CA");
        myClient.setCertificateValidator(validator);

        // Create application description
        ApplicationDescription appDescription = new ApplicationDescription();
        appDescription.setApplicationName(new LocalizedText(applicationName, Locale.ENGLISH));
        appDescription.setApplicationUri("urn:localhost:UA:"+applicationName);
        appDescription.setProductUri("urn:prosysopc.com:UA:"+applicationName);
        appDescription.setApplicationType(ApplicationType.Client);

        // Create and set application identity
        ApplicationIdentity identity =  new ApplicationIdentity();
        identity.setApplicationDescription(appDescription);
        identity.setOrganisation("Prosys");
        myClient.setApplicationIdentity(identity);
//        添加监听（订阅）事件
        Subscription subscription = new Subscription();
//        设置监听的节点。可以监听具体的某个值，可以监听多个节点
        MonitoredDataItem item = new MonitoredDataItem(new NodeId(2,"MyEnumObject"));
//        添加监听事件，服务器端数据改变是本地对应的动作设置
        item.setDataChangeListener(new MonitoredDataItemListener() {
            /**
             *
             * @param monitoredDataItem
             * monitoredDataItem存储着节点的相关信息
             * @param dataValue
             * dataValue 上一次的value
             * @param dataValue1
             * 当前的value
             */
            @Override
            public void onDataChange(MonitoredDataItem monitoredDataItem, DataValue dataValue, DataValue dataValue1) {
//                Log.i("----DataValue----", dataValue.getValue() + "");
                Log.i("----DataValue1----", dataValue1.getValue() + "");
//               通知UI更新
                publishProgress(dataValue1.getValue().toString());
            }
        });
        try {
            subscription.addItem(item);
            myClient.addSubscription(subscription);
        } catch (ServiceException e) {
            e.printStackTrace();
        } catch (StatusException e) {
            e.printStackTrace();
        }
        // Set locale
        myClient.setLocale(Locale.ENGLISH);

        // Set default timeout to 60 seconds
        myClient.setTimeout(60000);

        // Set security mode to NONE (others not currently supported on Android)
        myClient.setSecurityMode(SecurityMode.NONE);

//		添加UserIdentiy 里面可以封装用户名密码秘钥等信息
        myClient.setUserIdentity(new UserIdentity());

        return myClient;
    }

    @Override
    protected void onProgressUpdate(String... values) {
        super.onProgressUpdate(values);
        Log.i("----onProgressUpdate----", values[0]);
//        value 更新
        activity.setValue(values[0]);
    }

    protected void onPostExecute(Boolean success) {
        String result = null;
        if(success)
            // If the operation was a success, show the time on the UI
            result = value.toString();
        else
            // If we got a failure, show the exception
            result = "Error: " + error;
        activity.setValue(result);
    }
}